home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Info-Mac 3
/
Info_Mac_1994-01.iso
/
Applications
/
Fractal Generator
/
Documentation
/
IFS-Manual.txt
< prev
next >
Wrap
Text File
|
1993-06-07
|
38KB
|
1,063 lines
FRACTAL LAB KIT
IFS mappings module
Ronald T. Kneusel
May 25, 1993
version 1.0
Table of Contents
I. Introduction
What is this all about?................................. 3
Fractals and IFS (Iterated Function System)............. 5
Getting started......................................... 10
II. Tutorial
A sample session........................................ 11
Using preset fractal maps............................... 12
Using basic commands.................................... 12
Using the FindMap command, an example.................. 15
III. Advanced features
A very brief introduction to programming in Forth....... 16
An example : the Sierpinski Triangle.................. 19
Basic Forth words....................................... 21
IV. Reference
Commands................................................ 22
Primitive words......................................... 25
Introduction
What is this all about?
The fractal lab kit is a command driven system for generating and
investigating fractal images. It is written using Chris Heilman's Pocket
Forth , a small Forth interpreter for the Macintosh. Pocket Forth is
available via anonymous FTP from archive.umich.edu in the directory
/mac/development/languages/.
The kit consists of a set of Forth words that allow the user to easily
create fractals based on IFS mappings. Because of it's small size and
generality, it should run on virtually all Macintosh computers. By
entering simple commands the user can define maps, draw the resultant
fractals in a variety of colors, show the orientation of the mappings,
measure positions within the image, and zoom in to view details. Fractals
using up to 12 maps can be generated.
Why not create a standard Macintosh application for all of this?
I used Forth for two reasons. First, I am still learning the language
and thought that this would be a good project towards that end.
Secondly, I have used several fractal programs in the past and while they
are excellent at what they do, they are rigid and inflexible. Creating a
system like this in Forth seemed ideal. Forth is fast and highly
interactive. It is also small and very easily extended. Not only does
the user have all the fractal commands, but they also have all of Forth
still at their disposal. A little programming can quickly extend the
existing capabilities. Pocket Forth was my choice for several reasons,
primarily, it is free and can be freely distributed, as well as supporting
floating point numbers to make life easier.
Fractal Lab Kit is freeware, if you use it and have any suggestions or
comments please let me know at the addresses below. I have plans for
additional 'modules' for investigating Mandelbrot and Julia sets, biomorph
images, and chaos in one and two dimensions. Your feedback will encourage
me to continue. Even if you have no specific comment, let me know where
you are so I can follow the program. I prefer postcards, but email is
good too.
Ron Kneusel
507 S. 92nd St.
Milwaukee, WI 53214
USA
kneusel@msupa.pa.msu.edu
or
rtk@herman.gem.valpo.edu
Fractals and IFS: an overview
A fractal is a geometric object with a non-integer dimension. We are
used to thinking in terms of Euclidean geometry, that is, in terms of
points, lines, areas (surfaces), and volumes (solids). Fractals do not
easily fit in such a framework and are difficult to comprehend (at least
for me). Common geometrical objects have integer dimensions:
Object Dimension
------ ----------
point 0 (no length or width or depth)
line 1 (length only, no width or depth)
plane 2 (length and width)
solid 3 (length, width and depth)
but fractals have non-integer dimensions, like 0.63... etc. How can this
be you say? Let's look at the simplest fractal of them all: the Cantor set.
To create the Cantor set imagine a line of length 1. Now, remove the
middle third of that line. Remove the middle third of the two remaining
lines. Continue removing the middle third an infinite number of times.
When you are finished the object you will be left with is a fractal with a
dimension that is not 0 (it's not a point) but is less than 1 (a line from
0 to 1 would contain all points, clearly a cantor set does not) and it can
be shown that the final dimension is ln2/ln3 = 0.6309297536.....
•••••• Begin Aside: Derivation of the Cantor Set dimension
One possible definition of dimension, the self-similar dimension, is the
ratio of the natural log of the number of intervals N (in 1-d) of length ß
needed to completely cover the set to the natural log of the reciprocal of
ß, taken in the limit that ß-->0. In the case of the Cantor set ß=(1/3)^n
where n is the "level" of the set. (Check: the second level has two
sections of length 1/3 while the next level has four sections of length
1/9 = (1/3)^2) So the condition ß-->0 becomes n-->∞ . Also, for the
Cantor set the number of intervals to cover the set at the level n is
N=2^n . (Check: at the second level there are 2^1 = 2 intervals, at the
third level there are 2^2=4 intervals and so on.) So we write:
lim lim
D = n-->∞ ln N / ln (1/ß) = n-->∞ ln (2^n) / ln ( 1/(1/3)^n)
lim
D = n-->∞ n ln 2 / n ln 3 = ln2 / ln3 = 0.6309297536.....
•••••• End Aside
The Cantor set, like other purely mathematical fractals, is completely
self-similar. That is, it looks identical on different scales (actually
it is independent of scale). Take a piece of paper (you do have scrap
paper near the computer; don't you?) and draw the first few lines of the
Cantor set, one below the other:
-------------------------
-------- ---------
--- --- --- ---
etc.
(Yours will undoubtedly look better than mine)
If you look at what you have just drawn you will notice that if you
magnify a lower level it will look like one above it, the entire set is
made up of an infinite number of copies of itself. (Infinity shows up
frequently when talking about fractals) As this is a one dimensional
fractal it is not terribly interesting; the program draws two dimensional
fractals where life is a little less boring.
They are definitely odd, but fractals do turn up in many places in nature,
the nautilus shell (see the SPIRAL), your lungs and circulatory system
(see the TREE), etc. Some people even think that the distribution of
matter in the universe is a fractal.
What about fractals and chaos?
Fractals are often mentioned in connection with chaotic behavior of
dynamical systems. The link comes from the fact that the final attractor
(a strange attractor) of a dissipative dynamical system is a fractal
object. If you want to talk more about this, contact me at the above
address.
What is IFS?
IFS (Iterated Function System) is the means by which the program
generates images. It was developed by Michael Barnsley. IFS involves
defining a number of maps that in some way determine what the final
product will look like (more on that later). An initial point is chosen
(the origin is nice) and iterated (i.e. put it in - get something out -
put that something back in, etc.) . These are maps in the mathematical
sense - roughly, a way of transforming a collection of points into another
space or back into its own space as is the case here. The map used for
each iteration is chosen at random based on the assigned probability, the
higher the probability the more likely that map is chosen. After each
iteration the resulting point is plotted. As this process is continued
the fractal image is built. Changing the probability of a map can
dramatically affect the resulting image, so it might take a bit to get the
picture "just right". It should be noted that the IFS algorithm is the
heart of new data compression techniques that can achieve compression
ratios of up to 30:1.
In mathematical terms, a 2 dimensional map can be most easily represented
in matrix form. A matrix is similar to the two dimensional arrays used in
many programming languages. If we have a starting point (x,y) and we want
to find the transformed coordinates, (x',y'), we can write the
transformation in this way:
|x'| |a b| |x| |e|
|y'| = |c d| |y| + |f|
This is equivalent to writing two equations:
x' = a*x + b*y + e
y' = c*x + d*y + f
The 2x2 matrix controls the reorientation of the initial coordinate system
while the vector (e f) is an offset to a new origin point for the map.
Finding the "magic" numbers for an IFS transformation
By way of example, I will show how to find the matrix values that
generate what has become known as the Mandelbrot Dragon. While the dragon
is usually generated according to a prescription (like the Cantor set
above) it can also be found using two mappings (i.e. two matrices).
Recalling that a fractal is made up of an infinite number of copies of
itself, we need only specify the "first" copy and the IFS algorithm will
fill in the rest. Therefore, imagine a square from 0 to 1, this is the
starting point as it were. We must transform the points from this square
into a different square (or squares), where the number of transformations
equals the number of "parts" that the fractal is made up of. The dragon
is made up of two parts: a contracted 45 degree rotation of the coordinate
axes and a contracted -45 degree rotation (with a flip). Perhaps the best
way to imagine this is to picture an arrow: ____________\_ from 0 to
1, the head of the arrow is only a half head so we can see if there is a
flip as well as a rotation and translation. After some thought we realize
that we need something like the following to generate the dragon: Again
take a piece of paper and draw a 2 inch arrow as above, the head of the
arrow is on the right and the barb is pointing north. Now, draw another
arrow from the left edge of the first going at a 45 degree angle until it
intersects an imaginary line running north to south that passes through
the midpoint of the first line. Draw the barb of this arrow on the left
side of the right endpoint of this line. Finally, complete the triangle
and draw the barb of this arrow on the left side and touching the head of
the second arrow. When you are finished you will have something like
this:
( see the MacPaint file 'Dragon Picture' )
where the directions of the arrow heads are crudely indicated. Finally,
complete each of the three squares determined by the arrows as one edge.
Now comes the fun part, how do we change the drawing into the numbers
for the maps? To find the maps we need to solve, for each map, two
systems of three linear equations since there are six numbers to find. To
write the six equations we must know where at least three points of the
original square (the one from 0 to 1) map to in the new maps. This is
where the arrow head directions become important. The arrow determines
two points for us, the head and the tail, while the last point can be
either of the two corners of the original square and where they map to in
the final square. So, to this end, label the tail and head of the first
arrow drawn (a1,a2) and (b1,b2) respectively, and label the corner of the
square above (a1,a2) as (c1,c2). These are the original three points, now
label the corresponding points in the second square (the one at a positive
45 degree angle to the first) as (A1,A2) for the tail (in this case they
are the same point) and (B1,B2) for the head. Label the farthest left
corner of the square (C1,C2).
Once this is done, we can write the following six equations to determine
the first map:
a1*a + a2*b + e = A1
b1*a + b2*b + e = B1
c1*a + c2*b + e = C1
and
a1*c + a2*d + f = A2
b1*c + b2*d + f = B2
c1*c + c2*d + f = C2
In order to get actual numbers, we need to impose a coordinate system.
Draw an x and y axis where the first arrow goes from 0 to 1 on the x axis
and left edge of the first square goes from 0 to 1 on the y axis. In this
coordinate system, (a1,a2)=(0,0); (b1,b2)=(1,0); (c1,c2)=(0,1) and the
points for the first map are (A1,A2)=(0,0); (B1,B2)=(0.5,0.5);
(C1,C2)= (-0.5,0.5).
The values for the matrix and vector are found by solving the two
systems. Cramer's Rule allows the solutions to be written as:
|A1 a2 1| |a1 A1 1| |a1 a2 A1|
|B1 b2 1| |b1 B1 1| |b1 b2 B1|
|C1 c2 1| |c1 C1 1| |c1 c2 C1|
a = --------- b = --------- e = ----------
|a1 a2 1| |a1 a2 1| |a1 a2 1 |
|b1 b2 1| |b1 b2 1| |b1 b2 1 |
|c1 c2 1| |c1 c2 1| |c1 c2 1 |
Where the vertical lines represent the determinant (not the matrix as I
have been using them for previously) and with a corresponding set for the
c, d, and f values. With these we find that the first transformation is:
|x'| |0.5 -0.5| |x| |0|
|y'| = |0.5 0.5| |y| + |0|
and applying the above to the second map gives:
|x'| |-0.5 -0.5| |x| |1|
|y'| = | 0.5 -0.5| |y| + |0|
(I will leave the actual solution as an exercise.....)
The last thing to consider is what sort of probability we want to assign
to each of these maps. Since there is no reason to favor one map to
another we can in this case get away with a probability of 0.5 for each
(remember, probabilities should add to 1). This is not always the case,
though.
There are many good books on fractals and chaos at all levels, check the
local book store or library. The book "Chaos: The Making of a New
Science" by John Gleick is a good place to start, though it is lean on the
technical aspects.
Getting Started
The IFS module includes a few different files. Double click the file
Fractal Lab Kit to get things going. It contains the core IFS words.
The file IFS-Maps contains about a dozen predefined fractal maps that will
illustrate much of the versatility that can be obtained. (Thanks to Dr.
Dale Snider, UW-Milwaukee Dept. of Physics, for the maps). Use Open
under the File menu to load the maps. Enter the command PRESET to choose
a map.
The commands you enter are really just Forth words. In fact, you are
really using Pocket Forth with the IFS words already defined, however,
you need not be familiar with Forth to use the program.
Tutorial
A Sample Session
In this sample session and what follows, things the user types are
indicated in bold while the computer's response is in plain text.
<after double-clicking the Fractal Lab Kit icon...>
ok _open <return>
<choose the IFS-Maps file from the standard Mac open dialog>
ok _fern green color on outlines draw
<program loads the maps for the fern, draws the outlines of the maps,
waits for a keypress, and draws the fern in green until the user presses a
key>
ok _mouse
<program shows the true coordinates of the mouse pointer until the user
presses a key>
ok _settings
Current plot origin ( 0.00000 , 0.00000 )
Current screen origin ( 100 , 330 )
Current x & y scale is 1.0000 : 1.0000
Axes are currently OFF
Draw Outlines is currently ON
Current number of maps = 5
ok _off outlines 0.178 0.034 origin .25 range cdraw
<program zooms in to the second leaflet and generates a magnified image
using a different color for each map until a keypress>
ok _bye
<program exits>
Using the Preset Fractal Maps
The file IFS-Maps contains code for about a dozen fractals. Use the
word open or Open from the File menu to load the file. The command preset
will bring a menu allowing the user to choose a particular fractal. Once
the maps are loaded, the fractal can be generated by typing draw. All of
the preset fractals should appear well centered on the screen, though to
see all of the tree enter 250 330 screen draw to adjust the screen origin
so that the entire image will fit, then enter reset to restore the default
settings.
At present, there is no way to store or print the images other than the
open-apple-shift-3 command. They can then be loaded into TeachText and
from there to any paint type program.
Basic Commands
A list of the basic, and most interactive, commands are presented along
with an example of their use. These are the minimum commands necessary to
use the program:
draw
Draw a fractal based on the current maps. Press a key to stop.
E.g. green color fern draw
cdraw
Except for plotting each map in a different color, it is the same as
draw.
E.g. spiral cdraw
<n> edit
Edit the n-th map. Enter a new value or press return to leave the
existing value as is.
E.g. 2 edit
a = 0.5 ?-0.5 (new value)
b = -0.5 ?<return> etc.
zero-maps
Erase all twelve maps.
E.g. zero-maps
<color.name> color
Set the current drawing color to the color named. Valid colors are
black, wite, red, green, blue, yellow, cyan, magenta
E.g. magenta color
<n> maps
Set the number of maps to use to <n>.
E.g. 4 maps
<x> <y> origin
Set the origin to (x,y). X and Y are floating point numbers.
E.g. -0.354 .789 origin
<u> <v> screen
Set the screen origin to (u,v) (pixels).
E.g. 120 220 screen
<r> range
Set the range to <r> (floating point). The viewing window is a
square with the lower left corner as the origin and side length
as range.
E.g. 0.5 range
<x> <y> scale
Set the x-axis and y-axis scales to the floating point values given.
The default scale is 1.0 for a full screen image. Changing the scale
to a value less than one shrinks the image, greater than one expands
the image.
E.g. 2.0 2.0 scale
mouse
When issued, mouse will translate the position of the pointer into
an x,y coordinate allowing the user to 'see' where certain parts of
the image are. Clicking the mouse button between two points will
measure the distance between them. Press a key to exit.
on|off axes
Turn the coordinate axes (really a mark on the origin) ON or OFF.
E.g. off axes
on|off outlines
Set showing the map outlines on or off, press a key to continue
after viewing the outlines.
E.g. on outlines
settings
Show a list of the current origin, screen origin, range, scale, number
of maps and whether the axes and outlines are on or off.
E.g. settings
findmap
Allows the user to enter three initial coordinates and three image
coordinates and calculates the map for those values.
E.g. findmap
make
Puts the most recent values from findmap on the stack in order
for set. The user needs to add the probability and map number
before calling set.
E.g. make .333 1 set
<a> <b> <c> <d> <e> <f> <p> <n> set
Sets the parameters for a map. The letters a-f correspond to the
values for the matrix and offset vector, <p> is the probability for
the map and <n> is the map number. All values except <n> are to
be floating point numbers.
E.g. 0.5 -0.5 0.5 0.5 0.0 0.0 0.5 1 set
<m1> <m2> copy
Copy map number <m1> to <m2> without disturbing <m1>.
E.g. 2 5 copy
<m> delete
Delete map number <m> and move any other maps up in memory.
E.g. 3 delete
<m> insert
Insert a blank map before map <m>.
E.g. 1 insert
cls
Clear the window.
E.g. cls
bye
Exit Fractal Lab Kit.
E.g. bye
Using the FindMap command : an example
The FindMap command is perhaps the most useful command. It allows the
user to find the parameters for a map by entering the coordinates and
where they map to. This example will use the FindMap command to calculate
the maps to find the Mandelbrot dragon which was introduced above.
With in the program enter findmap. You will see be asked to enter the
coordinates of three points from the original map. The origin, the lower
right and upper left corners of the initial box (remember, it goes from
0..1 in both x and y) make good starting places. Therefore, enter 0 for
x1 and 0 for y1, (1,0) for (x2,y2), and (0,1) for (x3,y3). You do not
need to enter a decimal point with each number in this case, you can also
press return to use the previously set value if desired (though it is not
shown). For the image points, enter (x1',y1') as (0,0), (x2',y2') as
(0.5,0.5) and (x3',y3') as (-0.5,0.5). The program will calculate the
appropriate map and display its values. At the prompt, enter make 0.5 1
set to make this newly calculated map the first map. Enter findmap again
and press return for each of the original points since we will use the
same ones as before. For the image points enter (x1',y1') as (1,0),
(x2',y2') as (0.5,0.5) and (x3',y3') as (0.5,-0.5). Then enter make 0.5 2
set to fix this as the second map. Lastly, enter 2 maps 120 220 screen
cdraw to use two maps, adjust the screen origin so the image will fit, and
draw using color.
Advanced Features
A very (very) brief introduction to programming in Forth
Forth is an interpreted, stack based programming language known for its
speed and extensibility. This is not an attempt to completely teach Forth
so much as to teach a little about Forth so that the user who is
unfamiliar with Forth can make some use of the language.
Forth is a stack based language, data is manipulated using a stack that
works in a way very similar to the lunch trays in a cafeteria. The last
tray in the stack is the first one out. Because of this, all mathematical
operations are in postfix format, i.e., instead of typing 4 + 7 one would
type 4 7 + which would leave the value 11 on the top of the stack. This
illustrates an important thing to remember about using Forth, anything
that is entered is interpreted as either a word in the dictionary (more on
that later) or a number to be pushed on the stack, so entering 4 7 + told
Forth to push a 4 on the stack followed by a 7 and the + word adds the top
two stack items. To see the value stored on the top of the stack use the
. word. Note that this is a destructive operation, it prints the value at
the top of the stack and removes it from the stack as well. To see the
top stack value but NOT remove it you need to enter dup . to first
duplicate the top item and then print it. By default, Forth only operates
on 16-bit integers but Pocket Forth supports real numbers as well. Forth
will interpret a value as a real number ONLY if it contains a decimal
point! It is therefore important to enter a decimal point for every
number that should be a real number and to NOT use one on numbers that
should be integers.
Forth supports the standard arithmetic operations: +, -, *, / (integers)
and f+, f-, f*, f/ (real numbers). Use f. to print the top of stack as a
real number. fdup duplicates the real number at the top of the stack
while fswap will switch the top two real numbers on the stack. These few
words will allow for using Forth as a simple calculator. Forth does not
support higher mathematical functions.
Forth derives its extensibility from the way in which programs are
written. As Forth interprets tokens from the input line (anything
surrounded by spaces is a token) it either pushes it on the stack as a
number or looks it up as a word in its dictionary. A Forth program,
therefore, consists of adding definitions to the dictionary. Definitions
are begin with the : word and end with a semi-colon. Once defined, the
word can be used in subsequent definitions. Parameters are passed via the
stack. Forth does allow for the use of variables and constants, though
these are slower than the stack. Use the word variable (or fvariable)
followed by the name for the variable to create one. Use <value> constant
( or fconstant) <name> do define a constant. Examples: typing fvariable
stddev will create room in the dictionary for a floating point variable
named stddev while typing 3.141592 fconstant PI will create a constant for
pi. Constants are really special words that push the value on the stack
so that typing pi will cause the value to be pushed on the stack.
However, entering the name of a variable will NOT place its value on the
stack, but rather, the address where the variable is stored will be placed
on the stack. To get the value of a variable a two word combination must
be used: stddev f@ will 'fetch' a floating point number stored at the
address that stddev places on the stack. Similarly, the value of an
integer variable is found using @ instead of f@. To store a value in a
variable, use ! or f! : 3 age ! or 1.414 sqr2 f!.
Forth uses several standard control structures: if else then, do loop
(or +loop), begin until, begin while repeat. The phrase
count @ 100 < if ." Yes, there is room" cr
else ." No, there is no room." cr then
will check whether the current value of count is less than 100 or not.
Forth supports <, >, = for comparing integer values. Pocket Forth has a
single word for comparing floating point numbers, fcompare, which returns
a -1 if f1<f2, 0 is f1=f2, and +1 if f1>f2, where f1 and f2 are the top
two stack numbers (assumed to be floating point). It is important to note
that unlike most other Forth words, fcompare does not remove the top two
floating point numbers.
The do loop is similar to the for loops in other languages. As might be
expected, the syntax is <hi> <lo> do <body> loop where the index (pushed
on the stack by the word r) will go from <lo> to <hi>-1. A variation is
to use +loop instead of loop to jump by the value on the top of the stack
(which must be positive). Begin until and begin while repeat are for
bottom tested and top tested conditional loops. The condition is the same
as for the if statement:
0 begin ." Hello" cr 1+ dup 100 < until
will print the word 'Hello' 100 times. Similarly, this fragment will also
print 'Hello' 100 times:
0 begin dup 99 < while ." Hello" cr 1+ repeat
Putting it all together
The following examples will illustrate the creation of simple Forth
words, after which an example using fractal generating words will be
presented.
1. Averaging four numbers
: ave4 ( a b c d -- average ) + + + 4 / ;
Using integer arithmetic, sum the top four stack items and divide the
result by 4. Illustrates comments which are anything surrounded by (),
note the space after the (. The comment given is known as a stack effect
comment and shows what effect the word has on the stack. Initial stack
items are on the left of the -- and the result is on the right.
2. Averaging N floating point numbers
: averageN ( a1. ... aN. N -- average. )
dup >r ( save N on the return stack )
1- 0 do ( adjust N and add the values )
f+ loop
r> ( get N off the return stack )
0 d>f f/ ; ( make it real and divide to find average )
This example illustrates use of the return stack. The return stack is the
place where Forth places addresses to return to when the current word is
done executing. While a word is executing it is possible to use the
return stack for temporary storage, but one must be careful to make sure
that all values placed on the stack by >r are removed using r> before the
word is done, otherwise Forth will attempt to return to ??? and very
likely crash. The way to convert an integer to a real number is to use
the words 0 d>f. This transforms the integer into a double length integer
and then into a real number.
3. Evaluating a function: Y = 3.4 * EXP (X^2)
fvariable x
: sqr ( x. -- x.*x. ) fdup f* ;
: cube ( x. -- x.^3 ) fdup fdup f* f* ;
: expf ( x. -- exp[x.] ) ( use Taylor series approx. )
fdup x f! 1.0 f+ x f@ sqr 2.0 f/ f+ x f@ cube 6.0 f/ f+ ;
: Y ( x. -- Y[x.] ) expf 3.4 f* ;
This is an example of factoring: the code for the square and cube could
easily have been left in the definition of expf but factoring them out
made the definition shorter and easier to read. In theory, according to
some, a properly factored Forth program, combined with well chosen word
names and stack effect comment, should be nearly self-documenting.
These examples are brief, but hopefully should be sufficient, especially
when combined with a list of Forth words, to allow writing of simple words
to extend the power of the program.
The Sierpinski Triangle : an example
The Sierpinski Triangle is a commonly seen fractal consisting of a
triangle that is made up of triangles. This will serve as an example of
how the program can be extended by adding words to the Forth dictionary.
The triangle is made up of three maps that divide the region 0..1 in x and
0..1 in y into three equal squares. We will develop a Forth word that
will find the maps for the triangle and then generate the fractal.
First, we must determine the maps. The findmap command's interactive
nature is unsuited to our task, fortunately, there are three 'primitive'
(i.e. non-interactive) words that will perform the same task: initial,
image, and solve. These words operate as follows:
<x1> <y1> <x2> <y2> <x3> <y3> initial
Sets the initial points for finding a map, (x1,y1),(x2,y2),(x3,y3).
<X1> <Y1> <X2> <Y2> <X3> <Y3> image
Sets the image points for finding a map, (X1,Y1),(X2,Y2),(X3,Y3).
solve
Finds the values that will map the initial points to the image points.
These words, when combined with make and set, will allow us to create a
single Forth word to find all three maps at once. At this point, then, we
can write:
: sierpinski ( generates the Sierpinski Triangle)
( Set up initial values, for all maps )
0.0 0.0 1.0 0.0 0.0 1.0 initial
( First map )
0.0 0.0 0.5 0.0 0.0 0.5 image solve
make 0.333 1 set
( Second map )
0.5 0.0 1.0 0.0 0.5 0.5 image solve
make 0.333 2 set
( Third map )
0.25 0.5 0.75 0.5 0.25 1.0 image solve
make 0.333 3 set
Now before viewing the fractal show the maps, reset the program and show
the settings, and draw the outlines:
( Show the maps )
page ." The Sierpinski maps: " cr showmaps
reset settings
key drop ( wait for a key press )
( Show outlines when drawing )
on outlines
( Reset the program and draw the fractal )
cdraw ;
Try this word and see what happens.
Basic Forth words
Below is a list of some basic Forth words and their use. With these it
should be possible to define your own words for use with the program.
Word Use
swap ( a b -- b a ) Switch top two stack items
dup ( a -- a a ) Duplicate top of stack
over ( a b -- a b a ) Bring 2nd to top
rot ( a b c -- b c a ) Rotate stack items
variable ( -- ) Make a variable of next token
constant ( a -- ) Make a constant of next token
+, -, *, / ( a b -- a$b ) Math, where $ is an operation
mod ( a b -- a mod b ) Remainder after dividing
drop ( a -- ) Drop the top stack item
cr ( -- ) Print a return character
space ( -- ) Print a space (ASCII 32)
emit ( a -- ) Print the character whose code
is on the stack
." ( -- ) Print text until a " found
. ( a -- ) Print the top of stack
key ( -- a ) Get a key, ASCII code on stack
bye ( -- ) Exit from Forth
open ( -- ) Load a file from disk
?terminal ( -- b ) Has a key been pressed?
( ( -- ) Start a comment (remember space)
!pen ( x y -- ) Move the pen to (x,y) (pixels)
-to ( x y -- ) Line from current to (x,y)
page ( -- ) Clear the screen
--> ( -- ) Load filename, no spaces!
open ( -- ) Load file chosen in Mac dialog
?button ( -- t ) Mouse button down?
@mouse ( -- x y ) Push mouse position on stack
save ( -- ) Save the current dictionary. This is PERMANANT!
Only use a copy! Once saved, the words you defined will be available
immediately when the program is next run.
See the reference section for more words that are program specific. Words
in plain text are special to Pocket Forth and may not be available on
other Forth systems, though there will likely be something like them.
Those interested in seriously learning Forth (some swear that it is the
best computer language there is) should get a hold of the book Starting
Forth by Leo Brodie (2nd ed. 1987), it is an excellent introduction.
Reference
Commands
draw
Draw a fractal based on the current maps. Press a key to stop.
E.g. green color fern draw
cdraw
Except for plotting each map in a different color, it is the same as
draw.
E.g. spiral cdraw
<n> idraw or <n> icdraw
Same as draw and cdraw respectively except for iterating through
<n>*500 points. Useful for drawing a fractal and stopping without
user interaction.
<n> edit
Edit the n-th map. Enter a new value or press return to leave the
existing value as is.
E.g. 2 edit
a = 0.5 ?-0.5 (new value)
b = -0.5 ?<return> etc.
zero-maps
Erase all twelve maps.
E.g. zero-maps
<color.name> color
Set the current drawing color to the color named. Valid colors are
black, wite, red, green, blue, yellow, cyan, magenta
E.g. magenta color
<n> maps
Set the number of maps to use to <n>.
E.g. 4 maps
<x> <y> origin
Set the origin to (x,y). X and Y are floating point numbers.
E.g. -0.354 .789 origin
<u> <v> screen
Set the screen origin to (u,v) (pixels).
E.g. 120 220 screen
<r> range
Set the range to <r> (floating point). The viewing window is a
square with the lower left corner as the origin and side length
as range.
E.g. 0.5 range
<x> <y> scale
Set the x-axis and y-axis scales to the floating point values given.
The default scale is 1.0 for a full screen image. Changing the scale
to a value less than one shrinks the image, greater than one expands
the image.
E.g. 2.0 2.0 scale
mouse
When issued, mouse will translate the position of the pointer into
an x,y coordinate allowing the user to 'see' where certain parts of
the image are. Clicking the mouse button between two points will
measure the distance between them. Press a key to exit.
on|off clear
Turn clearing of page before drawing on and off. Default is on.
on|off axes
Turn the coordinate axes (really a mark on the origin) ON or OFF.
E.g. off axes
on|off outlines
Set showing the map outlines on or off, press a key to continue
after viewing the outlines.
E.g. on outlines
settings
Show a list of the current origin, screen origin, range, scale, number
of maps and whether the axes and outlines are on or off.
E.g. settings
findmap
Allows the user to enter three initial coordinates and three image
coordinates and calculates the map for those values.
E.g. findmap
make
Puts the most recent values from findmap on the stack in order
for set. The user needs to add the probability and map number
before calling set.
E.g. make .333 1 set
<a> <b> <c> <d> <e> <f> <p> <n> set
Sets the parameters for a map. The letters a-f correspond to the
values for the matrix and offset vector, <p> is the probability for
the map and <n> is the map number. All values except <n> are to
be floating point numbers.
E.g. 0.5 -0.5 0.5 0.5 0.0 0.0 0.5 1 set
<m1> <m2> copy
Copy map number <m1> to <m2> without disturbing <m1>.
E.g. 2 5 copy
<m> delete
Delete map number <m> and move any other maps up in memory.
E.g. 3 delete
<m> insert
Insert a blank map before map <m>.
E.g. 1 insert
cls
Clear the window.
E.g. cls
bye
Exit Fractal Lab Kit.
E.g. bye
<9|12|13> monitor
Set the program for a 9, 12, or 13 inch monitor.
E.g. 13 monitor
mem
Show the available dictionary space. (Forth only has 32k)
E.g. mem
?origin, ?screen, ?scale, ?range, ?maps, ?axes, ?outline, ?clear
Show individual settings. settings calls each of these.
<n> show
Show the values of map <n>.
E.g. 3 show
Primitive commands
These commands (words) are 'primitive' in the sense that they are called
by the regular command words. Since they are standard Forth words they
are available for user use as well.
input ( -- a )
Get a 16-bit integer on the stack.
finput ( -- f b )
Get a floating point number on the stack and a boolean value that is
true if the user pressed the return key only, in which case the
number is 0.0.
#map->addr ( a -- addr )
Convert a number for a map into an address to the map location in
memory.
get ( offset map# -- value )
Get a value for a particular map. The offset is a branch into the
map, each value is 10 bytes long. The constants a,b,c,d,e,f and p
are defined to give the proper offset: c 3 get returns the c value
of the third map.
update ( value offset map# -- )
Put the value in the numbered map at the offset (use a-f or p).
print ( addr -- )
Print the map starting at addr.
wsize ( h v -- )
Resize the window to h pixels high and v pixels across.
rand ( -- f )
Put a random floating point number from 0..1 on the stack.
dot ( u v -- )
Draw a dot on the screen at (u,v) (pixels).
plot ( x. y. -- )
Plot the point (x,y) on the screen.
plotto ( x. y. -- )
Draw a line from the last plotted point to (x,y).
determinant ( -- d )
Find the determinant of the 3x3 matrix whose values are stored
in the floating point variables d1 through d9. Values in the form:
[ [d1,d2,d3],[d4,d5,d6].[d7,d8,d9]].
x->d ( -- )
Copy the values in x1,y1 .. x3,y3 to the matrix d. Used to setup for
finding a map.
xy->uv ( x. y. -- u v )
Change real coordinates (x,y) into screen coordinates (u,v). Call
factor first.
factor ( -- )
Calculates redundant factors for xy->uv to speed drawing.
firstpoints ( -- )
Get the initial points for a map, interactive.
solve3x3 ( -- f. d. c. e. b. a. )
Solve for a map, calculated values on stack. Call either firstpoints
and imagepoints or initial and image before calling solve3x3.
outputmap ( f. d. c. e. b. a. -- )
Display map values on the stack on the screen.